home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / app / user_install.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-09-19  |  46.1 KB  |  1,572 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  * Copyright (C) 2000 Michael Natterer and Sven Neumann
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18.  */
  19.  
  20. #include "config.h"
  21.  
  22. #include <string.h>
  23.  
  24. #include <glib.h>
  25.  
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <sys/types.h>
  29. #include <sys/stat.h>
  30. #ifdef HAVE_UNISTD_H
  31. #include <unistd.h>
  32. #endif
  33. #include <dirent.h>
  34.  
  35. #ifdef G_OS_WIN32
  36. #include <direct.h>
  37. #  ifndef S_ISDIR
  38. #  define S_ISDIR(m) (m & _S_IFDIR)
  39. #  define S_ISREG(m) (m & _S_IFREG)
  40. #  endif
  41. #endif
  42.  
  43. #include "apptypes.h"
  44.  
  45. #include "appenv.h"
  46. #include "gdisplay_ops.h"
  47. #include "gimprc.h"
  48. #include "gimpui.h"
  49. #include "resolution_calibrate.h"
  50. #include "unitrc.h"
  51. #include "user_install.h"
  52. #include "libgimp/gimpenv.h"
  53. #include "libgimp/gimplimits.h"
  54. #include "libgimp/gimpmath.h"
  55.  
  56. #include "libgimp/gimpintl.h"
  57.  
  58. #include "pixmaps/eek.xpm"
  59. #include "pixmaps/folder.xpm"
  60. #include "pixmaps/new.xpm"
  61. #include "pixmaps/wilber.xpm"
  62.  
  63. #ifdef G_OS_WIN32
  64. #  include <io.h>
  65. #  define mkdir(path, mode) _mkdir(path)
  66. #else
  67. #  ifndef __EMX__
  68. #    define USER_INSTALL "user_install"
  69. #  else
  70. #    include <process.h>
  71. #    define USER_INSTALL "user_install.cmd"
  72. #  endif
  73. #endif
  74.  
  75. #define NUM_PAGES    6
  76. #define EEK_PAGE     (NUM_PAGES - 1)
  77. #define WILBER_WIDTH 62
  78.  
  79. #define PAGE_STYLE(widget)  gtk_widget_set_style (widget, page_style)
  80. #define TITLE_STYLE(widget) gtk_widget_set_style (widget, title_style)
  81.  
  82. static void     user_install_dialog_create     (UserInstallCallback);
  83. static void     user_install_continue_callback (GtkWidget *widget, gpointer data);
  84. static void     user_install_cancel_callback   (GtkWidget *widget, gpointer data);
  85.  
  86. static gboolean user_install_run               (void);
  87. static void     user_install_tuning            (void);
  88. static void     user_install_tuning_done       (void);
  89. static void     user_install_resolution        (void);
  90. static void     user_install_resolution_done   (void);
  91.  
  92.  
  93. void
  94. user_install_verify (UserInstallCallback user_install_callback)
  95. {
  96.   gboolean properly_installed = TRUE;
  97.   gchar *filename;
  98.   struct stat stat_buf;
  99.  
  100.   /* gimp_directory now always returns something */
  101.   filename = gimp_directory ();
  102.  
  103.   if (stat (filename, &stat_buf) != 0)
  104.     properly_installed = FALSE;
  105.  
  106.   /*  If there is already a proper installation, invoke the callback  */
  107.   if (properly_installed)
  108.     {
  109.       (* user_install_callback) ();
  110.     }
  111.   /*  Otherwise, prepare for installation  */
  112.   else if (no_interface)
  113.     {
  114.       g_print (_("The GIMP is not properly installed for the current user\n"));
  115.       g_print (_("User installation was skipped because the '--nointerface' flag was encountered\n"));
  116.       g_print (_("To perform user installation, run the GIMP without the '--nointerface' flag\n"));
  117.  
  118.       (* user_install_callback) ();
  119.     }
  120.   else
  121.     {
  122.       user_install_dialog_create (user_install_callback);
  123.     }
  124. }
  125.  
  126. /*  private stuff  */
  127.  
  128. static GtkWidget *user_install_dialog = NULL;
  129.  
  130. static GtkWidget *notebook = NULL;
  131.  
  132. static GtkWidget *title_pixmap = NULL;
  133.  
  134. static GtkWidget *title_label  = NULL;
  135. static GtkWidget *footer_label = NULL;
  136.  
  137. static GtkWidget *log_page        = NULL;
  138. static GtkWidget *tuning_page     = NULL;
  139. static GtkWidget *resolution_page = NULL;
  140.  
  141. static GtkWidget *continue_button = NULL;
  142. static GtkWidget *cancel_button   = NULL;
  143.  
  144. static GtkStyle *title_style = NULL;
  145.  
  146. static GtkStyle    *page_style = NULL;
  147. static GdkColormap *colormap   = NULL;
  148.  
  149. static GdkGC *white_gc = NULL;
  150.  
  151. static GdkColor black_color;
  152. static GdkColor white_color;
  153. static GdkColor title_color;
  154.  
  155. typedef enum
  156.   {
  157.     TREE_ITEM_DONT,        /* Don't pre-create */
  158.     TREE_ITEM_MKDIR_ONLY,    /* Just mkdir */
  159.     TREE_ITEM_FROM_SYSCONF_DIR,    /* Copy from sysconf directory */
  160.     TREE_ITEM_FROM_DATA_DIR    /* ... from data directory */
  161.   } TreeItemType;
  162.  
  163. static struct
  164. {
  165.   gboolean     directory;
  166.   gchar       *text;
  167.   gchar       *description;    /* If NULL, don't show in tree */
  168.   TreeItemType type;
  169.   gchar       *source_filename;    /* If NULL, use text */
  170. }
  171. tree_items[] =
  172. {
  173.   {
  174.     FALSE, "gimprc",
  175.     N_("The gimprc is used to store personal preferences\n"
  176.        "that affect GIMP's default behavior.\n"
  177.        "Paths to search for brushes, palettes, gradients,\n"
  178.        "patterns, plug-ins and modules can also configured\n"
  179.        "here."),
  180.     TREE_ITEM_FROM_SYSCONF_DIR, "gimprc_user"
  181.   },
  182.   {
  183.     FALSE, "gtkrc",
  184.     N_("GIMP uses an additional gtkrc file so you can\n"
  185.        "configure it to look differently than other GTK apps."),
  186.     TREE_ITEM_FROM_SYSCONF_DIR, "gtkrc_user"
  187.   },
  188.   {
  189.     FALSE, "pluginrc",
  190.     N_("Plug-ins and extensions are external programs run\n"
  191.        "by the GIMP which provide additional functionality.\n"
  192.        "These programs are searched for at run-time and\n"
  193.        "information about their functionality and mod-times\n"
  194.        "is cached in this file.  This file is intended to\n"
  195.        "be GIMP-readable only, and should not be edited."),
  196.     TREE_ITEM_DONT, NULL
  197.   },
  198.   {
  199.     FALSE, "menurc",
  200.     N_("Key shortcuts can be dynamically redefined in The GIMP.\n"
  201.        "The menurc is a dump of your configuration so it can.\n"
  202.        "be remembered for the next session.  You may edit this\n"
  203.        "file if you wish, but it is much easier to define the\n"
  204.        "keys from within The GIMP.  Deleting this file will\n"
  205.        "restore the default shortcuts."),
  206.     TREE_ITEM_DONT, NULL
  207.   },
  208.   {
  209.     FALSE, "sessionrc",
  210.     N_("The sessionrc is used to store what dialog windows were\n"
  211.        "open the last time you quit The GIMP.  You can configure\n"
  212.        "The GIMP to reopen these dialogs at the saved position."),
  213.     TREE_ITEM_DONT, NULL
  214.   },
  215.   {
  216.     FALSE, "unitrc",
  217.     N_("The unitrc is used to store your user units database.\n"
  218.        "You can define additional units and use them just\n"
  219.        "like you use the built-in units inches, millimeters,\n"
  220.        "points and picas.  This file is overwritten each time\n"
  221.        "you quit the GIMP."),
  222.     TREE_ITEM_FROM_SYSCONF_DIR, NULL
  223.   },
  224.   {
  225.     TRUE, "brushes",
  226.     N_("This is a subdirectory which can be used to store\n"
  227.        "user defined brushes.  The default gimprc file\n"
  228.        "checks this subdirectory in addition to the system-\n"
  229.        "wide GIMP brushes installation when searching for\n"
  230.        "brushes."),
  231.     TREE_ITEM_MKDIR_ONLY, NULL
  232.   },
  233.   {
  234.     TRUE, "generated_brushes",
  235.     N_("This is a subdirectory which is used to store brushes\n"
  236.        "that are created with the brush editor.  The default\n"
  237.        "gimprc file checks this subdirectory when searching\n"
  238.        "for generated brushes."),
  239.     TREE_ITEM_MKDIR_ONLY, NULL
  240.   },
  241.   {
  242.     TRUE, "gradients",
  243.     N_("This is a subdirectory which can be used to store\n"
  244.        "user defined gradients.  The default gimprc file\n"
  245.        "checks this subdirectory in addition to the system-\n"
  246.        "wide GIMP gradients installation when searching\n"
  247.        "for gradients."),
  248.     TREE_ITEM_MKDIR_ONLY, NULL
  249.   },
  250.   {
  251.     TRUE, "palettes",
  252.     N_("This is a subdirectory which can be used to store\n"
  253.        "user defined palettes.  The default gimprc file\n"
  254.        "checks only this subdirectory (not the system-wide\n"
  255.        "installation) when searching for palettes.  During\n"
  256.        "installation, the system palettes will be copied\n"
  257.        "here.  This is done to allow modifications made to\n"
  258.        "palettes during GIMP execution to persist across\n"
  259.        "sessions."),
  260.     TREE_ITEM_FROM_DATA_DIR, NULL
  261.   },
  262.   {
  263.     TRUE, "patterns",
  264.     N_("This is a subdirectory which can be used to store\n"
  265.        "user defined patterns.  The default gimprc file\n"
  266.        "checks this subdirectory in addition to the system-\n"
  267.        "wide GIMP patterns installation when searching for\n"
  268.        "patterns."),
  269.     TREE_ITEM_MKDIR_ONLY, NULL
  270.   },
  271.   {
  272.     TRUE, "plug-ins",
  273.     N_("This is a subdirectory which can be used to store\n"
  274.        "user created, temporary, or otherwise non-system-\n"
  275.        "supported plug-ins.  The default gimprc file checks\n"
  276.        "this subdirectory in addition to the systemwide\n"
  277.        "GIMP plug-in directories when searching for plug-ins."),
  278.     TREE_ITEM_MKDIR_ONLY, NULL
  279.   },
  280.   {
  281.     TRUE, "modules",
  282.     N_("This subdirectory can be used to store user created,\n"
  283.        "temporary, or otherwise non-system-supported DLL\n"
  284.        "modules.  The default gimprc file checks this subdirectory\n"
  285.        "in addition to the system-wide GIMP module directory\n"
  286.        "when searching for modules to load when initializing."),
  287.     TREE_ITEM_MKDIR_ONLY, NULL
  288.   },
  289.   {
  290.     TRUE, "scripts",
  291.     N_("This subdirectory is used by the GIMP to store user\n"
  292.        "created and installed scripts.  The default gimprc file\n"
  293.        "checks this subdirectory in addition to the systemwide\n"
  294.        "GIMP scripts subdirectory when searching for scripts"),
  295.     TREE_ITEM_MKDIR_ONLY, NULL
  296.   },
  297.   {
  298.     TRUE, "tmp",
  299.     N_("This subdirectory is used by the GIMP to temporarily\n"
  300.        "store undo buffers to reduce memory usage.  If GIMP is\n"
  301.        "unceremoniously killed, files may persist in this directory\n"
  302.        "of the form: gimp<#>.<#>.  These files are useless across\n"
  303.        "GIMP sessions and can be destroyed with impunity."),
  304.     TREE_ITEM_MKDIR_ONLY, NULL
  305.   },
  306.   {
  307.     TRUE, "curves",
  308.     N_("This subdirectory is used to store parameter files for\n"
  309.        "the Curves tool."),
  310.     TREE_ITEM_MKDIR_ONLY, NULL
  311.   },
  312.   {
  313.     TRUE, "levels",
  314.     N_("This subdirectory is used to store parameter files for\n"
  315.        "the Levels tool."),
  316.     TREE_ITEM_MKDIR_ONLY, NULL
  317.   },
  318.   {
  319.     TRUE, "fractalexplorer",
  320.     N_("This is a subdirectory which can be used to store\n"
  321.        "user defined fractals to be used by the FractalExplorer\n"
  322.        "plug-in.  The default gimprc file checks this subdirectory\n"
  323.        "in addition to the systemwide GIMP FractalExplorer\n" 
  324.        "installation when searching for fractals."),
  325.     TREE_ITEM_MKDIR_ONLY, NULL
  326.   },  
  327.   {
  328.     TRUE, "gfig",
  329.     N_("This is a subdirectory which can be used to store\n"
  330.        "user defined figures to be used by the GFig plug-in.\n"
  331.        "The default gimprc file checks this subdirectory in\n"
  332.        "addition to the systemwide GIMP GFig installation\n"
  333.        "when searching for gfig figures."),
  334.     TREE_ITEM_MKDIR_ONLY, NULL
  335.   },
  336.   {
  337.     TRUE, "gflare",
  338.     N_("This is a subdirectory which can be used to store\n"
  339.        "user defined gflares to be used by the GFlare plug-in.\n"
  340.        "The default gimprc file checks this subdirectory in\n"
  341.        "addition to the systemwide GIMP GFlares installation\n"
  342.        "when searching for gflares."),
  343.     TREE_ITEM_MKDIR_ONLY, NULL
  344.   },
  345.   {
  346.     TRUE, "gimpressionist",
  347.     N_("This is a subdirectory which can be used to store\n"
  348.        "user defined data to be used by the Gimpressionist\n"
  349.        "plug-in.  The default gimprc file checks this subdirectory\n"
  350.        "in addition to the systemwide GIMP Gimpressionist\n"
  351.        "installation when searching for data."),
  352.     TREE_ITEM_MKDIR_ONLY, NULL
  353.   },
  354.   {
  355.     TRUE, "gimpressionist/Brushes",
  356.     NULL,
  357.     TREE_ITEM_MKDIR_ONLY, NULL
  358.   },
  359.   {
  360.     TRUE, "gimpressionist/Paper",
  361.     NULL,
  362.     TREE_ITEM_MKDIR_ONLY, NULL
  363.   },
  364.   {
  365.     TRUE, "gimpressionist/Presets",
  366.     NULL,
  367.     TREE_ITEM_MKDIR_ONLY, NULL
  368.   }
  369. };
  370. static gint num_tree_items = sizeof (tree_items) / sizeof (tree_items[0]);
  371.  
  372. static void
  373. user_install_notebook_set_page (GtkNotebook *notebook,
  374.                 gint         index)
  375. {
  376.   gchar *title;
  377.   gchar *footer;
  378.   GtkWidget *page;
  379.   
  380.   page = gtk_notebook_get_nth_page (notebook, index);
  381.   
  382.   title  = gtk_object_get_data (GTK_OBJECT (page), "title");
  383.   footer = gtk_object_get_data (GTK_OBJECT (page), "footer");
  384.  
  385.   gtk_label_set_text (GTK_LABEL (title_label), title);
  386.   gtk_label_set_text (GTK_LABEL (footer_label), footer);
  387.  
  388.   if (index == EEK_PAGE)
  389.     {
  390.       gtk_widget_set_usize (title_pixmap, 
  391.                 title_pixmap->allocation.width,
  392.                 title_pixmap->allocation.height);
  393.       gimp_pixmap_set (GIMP_PIXMAP (title_pixmap), eek_xpm);
  394.     }
  395.   
  396.   gtk_notebook_set_page (notebook, index);
  397. }
  398.  
  399. static void
  400. user_install_continue_callback (GtkWidget *widget,
  401.                 gpointer   data)
  402. {
  403.   static gint notebook_index = 0;
  404.   UserInstallCallback callback;
  405.  
  406.   callback = (UserInstallCallback) data;
  407.  
  408.   switch (notebook_index)
  409.     {
  410.     case 0:
  411.       break;
  412.       
  413.     case 1:
  414.       /*  Creatring the directories can take some time on NFS, so inform
  415.        *  the user and set the buttons insensitive
  416.        */
  417.       gtk_widget_set_sensitive (continue_button, FALSE);
  418.       gtk_widget_set_sensitive (cancel_button, FALSE);
  419.       gtk_label_set_text (GTK_LABEL (footer_label),
  420.               _("Please wait while your personal\n"
  421.                 "GIMP directory is being created..."));
  422.  
  423.       while (gtk_events_pending ())
  424.     gtk_main_iteration ();
  425.  
  426.       if (user_install_run ())
  427.     gtk_widget_set_sensitive (continue_button, TRUE);
  428.  
  429.       gtk_widget_set_sensitive (cancel_button, TRUE);
  430.       break;
  431.  
  432.     case 2:
  433.       parse_buffers_init ();
  434.       parse_unitrc ();
  435.       parse_gimprc ();
  436.       user_install_tuning ();
  437.       break;
  438.  
  439.     case 3:
  440.       user_install_tuning_done ();
  441.       user_install_resolution ();
  442.       break;
  443.  
  444.     case 4:
  445.       user_install_resolution_done ();
  446.  
  447.       gtk_widget_destroy (user_install_dialog);
  448.       gdk_gc_unref (white_gc);
  449.       gtk_style_unref (title_style);
  450.       gtk_style_unref (page_style);
  451.  
  452.       (* callback) ();
  453.       return;
  454.       break;
  455.  
  456.     case EEK_PAGE:
  457.     default:
  458.       g_assert_not_reached ();
  459.     }
  460.  
  461.   if (notebook_index < NUM_PAGES - 1)
  462.     user_install_notebook_set_page (GTK_NOTEBOOK (notebook), ++notebook_index);
  463. }
  464.  
  465.  
  466. static void
  467. user_install_cancel_callback (GtkWidget *widget,
  468.                   gpointer   data)
  469. {
  470.   static gint timeout = 0;
  471.  
  472.   if (timeout)
  473.     gtk_exit (0);
  474.  
  475.   gtk_widget_destroy (continue_button);
  476.   user_install_notebook_set_page (GTK_NOTEBOOK (notebook), EEK_PAGE);
  477.   timeout = gtk_timeout_add (1024, (GtkFunction)gtk_exit, (gpointer)0);
  478. }
  479.  
  480. static gint
  481. user_install_corner_expose (GtkWidget      *widget,
  482.                 GdkEventExpose *eevent,
  483.                 gpointer        data)
  484. {
  485.   switch ((GtkCornerType) data)
  486.     {
  487.     case GTK_CORNER_TOP_LEFT:
  488.       gdk_draw_arc (widget->window,
  489.             white_gc,
  490.             TRUE,
  491.             0, 0,
  492.             widget->allocation.width * 2,
  493.             widget->allocation.height * 2,
  494.             90 * 64,
  495.             180 * 64);
  496.       break;
  497.       
  498.     case GTK_CORNER_BOTTOM_LEFT:
  499.       gdk_draw_arc (widget->window,
  500.             white_gc,
  501.             TRUE,
  502.             0, -widget->allocation.height,
  503.             widget->allocation.width * 2,
  504.             widget->allocation.height * 2,
  505.             180 * 64,
  506.             270 * 64);
  507.       break;
  508.       
  509.     case GTK_CORNER_TOP_RIGHT:
  510.       gdk_draw_arc (widget->window,
  511.             white_gc,
  512.             TRUE,
  513.             -widget->allocation.width, 0,
  514.             widget->allocation.width * 2,
  515.             widget->allocation.height * 2,
  516.             0 * 64,
  517.             90 * 64);
  518.       break;
  519.       
  520.     case GTK_CORNER_BOTTOM_RIGHT:
  521.       gdk_draw_arc (widget->window,
  522.             white_gc,
  523.             TRUE,
  524.             -widget->allocation.width, -widget->allocation.height,
  525.             widget->allocation.width * 2,
  526.             widget->allocation.height * 2,
  527.             270 * 64,
  528.             360 * 64);
  529.       break;
  530.       
  531.     default:
  532.       return FALSE;
  533.     }
  534.  
  535.   return TRUE;
  536. }
  537.  
  538. static GtkWidget *
  539. user_install_notebook_append_page (GtkNotebook *notebook,
  540.                    gchar       *title,
  541.                    gchar       *footer)
  542. {
  543.   GtkWidget *page;
  544.   
  545.   page = gtk_vbox_new (FALSE, 6);
  546.   gtk_object_set_data (GTK_OBJECT (page), "title", title);
  547.   gtk_object_set_data (GTK_OBJECT (page), "footer", footer);
  548.   gtk_notebook_append_page (notebook, page, NULL);
  549.   gtk_widget_show (page);
  550.  
  551.   return page;
  552. }
  553.  
  554. static void
  555. add_label (GtkBox   *box,
  556.        gchar    *text)
  557. {
  558.   GtkWidget *label;
  559.  
  560.   label = gtk_label_new (text);
  561.   PAGE_STYLE (label);
  562.   gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
  563.  
  564.   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  565.   gtk_box_pack_start (box, label, FALSE, FALSE, 0);
  566.   
  567.   gtk_widget_show (label);
  568. }
  569.  
  570. static void
  571. user_install_ctree_select_row (GtkWidget      *widget,
  572.                    gint            row, 
  573.                    gint            column, 
  574.                    GdkEventButton *bevent,
  575.                    gpointer        data)
  576. {
  577.   GtkNotebook *notebook;
  578.  
  579.   notebook = (GtkNotebook*) data;
  580.  
  581.   gtk_notebook_set_page (notebook, row);
  582. }
  583.  
  584. void
  585. user_install_dialog_create (UserInstallCallback callback)
  586. {
  587.   GtkWidget *dialog;
  588.   GtkWidget *vbox;
  589.   GtkWidget *hbox;
  590.   GtkWidget *ebox;
  591.   GtkWidget *table;
  592.   GtkWidget *darea;
  593.   GtkWidget *page;
  594.   GtkWidget *sep;
  595.   GdkFont   *large_font;
  596.  
  597.   dialog = user_install_dialog =
  598.     gimp_dialog_new (_("GIMP User Installation"), "user_installation",
  599.              NULL, NULL,
  600.              GTK_WIN_POS_CENTER,
  601.              FALSE, FALSE, FALSE,
  602.  
  603.              _("Continue"), user_install_continue_callback,
  604.              callback, NULL, &continue_button, TRUE, FALSE,
  605.              _("Cancel"), user_install_cancel_callback,
  606.              callback, 1, &cancel_button, FALSE, TRUE,
  607.  
  608.              NULL);
  609.  
  610.   gimp_dialog_set_icon (GTK_WINDOW (dialog));
  611.  
  612.   gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area), 8);
  613.  
  614.   /*  hide the separator between the dialog's vbox and the action area  */
  615.   gtk_widget_destroy (GTK_WIDGET (g_list_nth_data (gtk_container_children (GTK_CONTAINER (GTK_BIN (dialog)->child)), 0)));
  616.  
  617.   gtk_widget_realize (dialog);
  618.  
  619.   /*  B/W Style for the page contents  */
  620.   page_style = gtk_style_copy (gtk_widget_get_default_style ());
  621.   colormap = gtk_widget_get_colormap (dialog);
  622.  
  623.   gdk_color_black (colormap, &black_color);
  624.   gdk_color_white (colormap, &white_color);
  625.  
  626.   page_style->fg[GTK_STATE_NORMAL]   = black_color;
  627.   page_style->text[GTK_STATE_NORMAL] = black_color;
  628.   page_style->bg[GTK_STATE_NORMAL]   = white_color;
  629.  
  630.   gdk_font_unref (page_style->font);
  631.   page_style->font = dialog->style->font;
  632.   gdk_font_ref (page_style->font);
  633.  
  634.   /*  B/Colored Style for the page title  */
  635.   title_style = gtk_style_copy (page_style);
  636.  
  637.   if (gdk_color_parse ("dark orange", &title_color) &&
  638.       gdk_colormap_alloc_color (colormap, &title_color, FALSE, TRUE))
  639.     {
  640.       title_style->bg[GTK_STATE_NORMAL] = title_color;
  641.     }
  642.  
  643.   /*  this is a fontset, e.g. multiple comma-separated font definitions  */
  644.   large_font = gdk_fontset_load (_("-*-helvetica-bold-r-normal-*-*-240-*-*-*-*-*-*,*"));
  645.  
  646.   if (large_font)
  647.     {
  648.       gdk_font_unref (title_style->font);
  649.       title_style->font = large_font;
  650.       gdk_font_ref (title_style->font);
  651.     }
  652.  
  653.   /*  W/W GC for the corner  */
  654.   white_gc = gdk_gc_new (dialog->window);
  655.   gdk_gc_set_foreground (white_gc, &white_color);
  656.  
  657.   TITLE_STYLE (dialog);
  658.  
  659.   footer_label = gtk_label_new (NULL);
  660.   PAGE_STYLE (footer_label);
  661.   gtk_label_set_justify (GTK_LABEL (footer_label), GTK_JUSTIFY_RIGHT);
  662.   gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->action_area), footer_label,
  663.             FALSE, FALSE, 8);
  664.   gtk_widget_show (footer_label);
  665.  
  666.   vbox = gtk_vbox_new (FALSE, 0);
  667.   gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), vbox);
  668.  
  669.   ebox = gtk_event_box_new ();
  670.   TITLE_STYLE (ebox);
  671.   gtk_widget_set_events (ebox, GDK_EXPOSURE_MASK);
  672.   gtk_widget_set_usize (ebox, WILBER_WIDTH + 16, -1);
  673.   gtk_box_pack_start (GTK_BOX (vbox), ebox, FALSE, FALSE, 0);
  674.   gtk_widget_show (ebox);
  675.  
  676.   hbox = gtk_hbox_new (FALSE, 8);
  677.   gtk_container_set_border_width (GTK_CONTAINER (hbox), 8);
  678.   gtk_container_add (GTK_CONTAINER (ebox), hbox);
  679.   gtk_widget_show (hbox);
  680.  
  681.   title_pixmap = gimp_pixmap_new (wilber_xpm);
  682.   gtk_box_pack_start (GTK_BOX (hbox), title_pixmap, FALSE, FALSE, 8);
  683.   gtk_widget_show (title_pixmap);
  684.  
  685.   title_label = gtk_label_new (NULL);
  686.   TITLE_STYLE (title_label);  
  687.   gtk_label_set_justify (GTK_LABEL (title_label), GTK_JUSTIFY_LEFT);
  688.   gtk_box_pack_start (GTK_BOX (hbox), title_label, FALSE, FALSE, 0);
  689.   gtk_widget_show (title_label);
  690.  
  691.   hbox = gtk_hbox_new (FALSE, 0);
  692.   gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
  693.   gtk_widget_show (hbox);
  694.  
  695.   ebox = gtk_event_box_new ();
  696.   TITLE_STYLE (ebox);  
  697.   gtk_widget_set_usize (ebox, 16, -1);
  698.   gtk_box_pack_start (GTK_BOX (hbox), ebox, FALSE, FALSE, 0);
  699.   gtk_widget_show (ebox);
  700.  
  701.   ebox = gtk_event_box_new ();
  702.   PAGE_STYLE (ebox);  
  703.   gtk_box_pack_start (GTK_BOX (hbox), ebox, TRUE, TRUE, 0);
  704.   gtk_widget_show (ebox);
  705.  
  706.   table = gtk_table_new (3, 3, FALSE);
  707.   gtk_table_set_col_spacing (GTK_TABLE (table), 1, 8);
  708.   gtk_container_add (GTK_CONTAINER (ebox), table);
  709.   gtk_widget_show (table);
  710.  
  711.   darea = gtk_drawing_area_new ();
  712.   TITLE_STYLE (darea);  
  713.   gtk_drawing_area_size (GTK_DRAWING_AREA (darea), 16, 16);
  714.   gtk_signal_connect_after (GTK_OBJECT (darea), "expose_event",
  715.                 GTK_SIGNAL_FUNC (user_install_corner_expose),
  716.                 (gpointer) GTK_CORNER_TOP_LEFT);
  717.   gtk_table_attach (GTK_TABLE (table), darea, 0, 1, 0, 1,
  718.             GTK_SHRINK, GTK_SHRINK, 0, 0);
  719.   gtk_widget_show (darea);
  720.  
  721.   darea = gtk_drawing_area_new ();
  722.   TITLE_STYLE (darea);  
  723.   gtk_drawing_area_size (GTK_DRAWING_AREA (darea), 16, 16);
  724.   gtk_signal_connect_after (GTK_OBJECT (darea), "expose_event",
  725.                 GTK_SIGNAL_FUNC (user_install_corner_expose),
  726.                 (gpointer) GTK_CORNER_BOTTOM_LEFT);
  727.   gtk_table_attach (GTK_TABLE (table), darea, 0, 1, 2, 3,
  728.             GTK_SHRINK, GTK_SHRINK, 0, 0);
  729.   gtk_widget_show (darea);
  730.  
  731.   notebook = gtk_notebook_new ();
  732.   gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook), FALSE);
  733.   gtk_notebook_set_show_border (GTK_NOTEBOOK (notebook), FALSE);
  734.   gtk_table_attach_defaults (GTK_TABLE (table), notebook, 1, 2, 1, 2);
  735.   gtk_widget_show (notebook);
  736.  
  737.   gtk_widget_show (vbox);
  738.  
  739.   /*  Page 1  */
  740.   page = user_install_notebook_append_page (GTK_NOTEBOOK (notebook),
  741.                         _("Welcome to\n"
  742.                           "The GIMP User Installation"),
  743.                         _("Click \"Continue\" to enter "
  744.                           "the GIMP user installation."));
  745.  
  746.   add_label (GTK_BOX (page),
  747.          _("The GIMP - GNU Image Manipulation Program\n"
  748.            "Copyright (C) 1995-2000\n"
  749.            "Spencer Kimball, Peter Mattis and the GIMP Development Team."));
  750.  
  751.   sep = gtk_hseparator_new ();
  752.   gtk_box_pack_start (GTK_BOX (page), sep, FALSE, FALSE, 2);
  753.   gtk_widget_show (sep);
  754.  
  755.   add_label (GTK_BOX (page),
  756.          _("This program is free software; you can redistribute it and/or modify\n"
  757.            "it under the terms of the GNU General Public License as published by\n"
  758.            "the Free Software Foundation; either version 2 of the License, or\n"
  759.            "(at your option) any later version."));
  760.   add_label (GTK_BOX (page),
  761.          _("This program is distributed in the hope that it will be useful,\n"
  762.            "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
  763.            "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
  764.            "See the GNU General Public License for more details."));
  765.   add_label (GTK_BOX (page),
  766.          _("You should have received a copy of the GNU General Public License\n"
  767.            "along with this program; if not, write to the Free Software\n"
  768.            "Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n"
  769.            "MA 02111-1307, USA."));
  770.  
  771.   /*  Page 2  */
  772.   {
  773.     GtkWidget *hbox;
  774.     GtkWidget *vbox;
  775.     GtkWidget *ctree;
  776.     GtkWidget *notebook2;
  777.     GtkWidget *page2;
  778.     GtkWidget *label;
  779.     GtkCTreeNode *main_node = NULL;
  780.     GtkCTreeNode *sub_node = NULL;
  781.     GdkPixmap *file_pixmap;
  782.     GdkBitmap *file_mask;
  783.     GdkPixmap *folder_pixmap;
  784.     GdkBitmap *folder_mask;
  785.     gchar     *str;
  786.  
  787.     gint i;
  788.  
  789.     gchar *node[1];
  790.     
  791.     page = user_install_notebook_append_page (GTK_NOTEBOOK (notebook),
  792.                           _("Personal GIMP Directory"),
  793.                           _("Click \"Continue\" to create "
  794.                         "your personal GIMP directory."));
  795.  
  796.     hbox = gtk_hbox_new (FALSE, 8);
  797.     gtk_box_pack_start (GTK_BOX (page), hbox, FALSE, FALSE, 0);
  798.     gtk_widget_show (hbox);
  799.  
  800.     ctree = gtk_ctree_new (1, 0);
  801.     PAGE_STYLE (ctree);
  802.     gtk_ctree_set_indent (GTK_CTREE (ctree), 12);
  803.     gtk_clist_set_shadow_type (GTK_CLIST (ctree), GTK_SHADOW_NONE);
  804.     gtk_clist_set_selection_mode (GTK_CLIST (ctree), GTK_SELECTION_BROWSE);
  805.     gtk_box_pack_start (GTK_BOX (hbox), ctree, FALSE, FALSE, 0);
  806.     gtk_widget_show (ctree);
  807.  
  808.     vbox = gtk_vbox_new (FALSE, 6);
  809.     gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
  810.     gtk_widget_show (vbox);
  811.  
  812.     str = g_strdup_printf (_("For a proper GIMP installation, a subdirectory named\n"
  813.                  "%s needs to be created."), gimp_directory ());
  814.     add_label (GTK_BOX (vbox), str);
  815.     g_free (str);
  816.  
  817.     add_label (GTK_BOX (vbox),
  818.            _("This subdirectory will contain a number of important files.\n"
  819.          "Click on one of the files or subdirectories in the tree\n"
  820.          "to get more information about the selected item."));
  821.  
  822.     notebook2 = gtk_notebook_new ();
  823.     gtk_container_set_border_width (GTK_CONTAINER (notebook2), 8);
  824.     gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook2), FALSE);
  825.     gtk_notebook_set_show_border (GTK_NOTEBOOK (notebook2), FALSE);
  826.     gtk_box_pack_start (GTK_BOX (vbox), notebook2, TRUE, TRUE, 0);
  827.     gtk_widget_show (notebook2);
  828.  
  829.     /*  empty page  */
  830.     page2 = gtk_vbox_new (FALSE, 0);
  831.     gtk_widget_show (page2);
  832.     gtk_notebook_append_page (GTK_NOTEBOOK (notebook2), page2, NULL);
  833.  
  834.     node[0] = gimp_directory ();
  835.  
  836.     main_node = gtk_ctree_insert_node (GTK_CTREE (ctree), NULL, NULL,
  837.                        node, 4,
  838.                        NULL, NULL, NULL, NULL,
  839.                        FALSE, TRUE);      
  840.  
  841.     gtk_signal_connect (GTK_OBJECT (ctree), "select_row",
  842.             GTK_SIGNAL_FUNC (user_install_ctree_select_row),
  843.             notebook2);
  844.  
  845.     file_pixmap = gdk_pixmap_create_from_xpm_d (dialog->window,
  846.                         &file_mask,
  847.                         &page_style->bg[GTK_STATE_NORMAL],
  848.                         new_xpm);
  849.     folder_pixmap = gdk_pixmap_create_from_xpm_d (dialog->window,
  850.                           &folder_mask,
  851.                           &page_style->bg[GTK_STATE_NORMAL],
  852.                           folder_xpm);
  853.  
  854.     for (i = 0; i < num_tree_items; i++)
  855.       {
  856.     if (tree_items[i].description == NULL)
  857.       continue;
  858.  
  859.     node[0] = tree_items[i].text;
  860.  
  861.     if (tree_items[i].directory)
  862.       {
  863.         sub_node = gtk_ctree_insert_node (GTK_CTREE (ctree), main_node, NULL,
  864.                           node, 4,
  865.                           folder_pixmap, folder_mask,
  866.                           folder_pixmap, folder_mask,
  867.                           FALSE, TRUE);      
  868.       }
  869.     else
  870.       {
  871.         sub_node = gtk_ctree_insert_node (GTK_CTREE (ctree), main_node, NULL,
  872.                           node, 4,
  873.                           file_pixmap, file_mask,
  874.                           file_pixmap, file_mask,
  875.                           FALSE, TRUE);
  876.       }
  877.  
  878.     page2 = gtk_vbox_new (FALSE, 0);
  879.     label = gtk_label_new (gettext (tree_items[i].description));
  880.     PAGE_STYLE (label);
  881.     PAGE_STYLE (label);
  882.     gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
  883.     gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  884.     gtk_box_pack_start (GTK_BOX (page2), label, TRUE, TRUE, 0);
  885.     gtk_widget_show (label);
  886.     gtk_widget_show (page2);
  887.  
  888.     gtk_notebook_append_page (GTK_NOTEBOOK (notebook2), page2, NULL);
  889.       }
  890.  
  891.     gtk_clist_set_column_width (GTK_CLIST (ctree), 0,
  892.                 gtk_clist_optimal_column_width (GTK_CLIST (ctree), 0));
  893.  
  894.     gtk_widget_set_usize (ctree, -1, ctree->requisition.height);
  895.  
  896.     gdk_pixmap_unref (file_pixmap);
  897.     gdk_bitmap_unref (file_mask);
  898.     gdk_pixmap_unref (folder_pixmap);
  899.     gdk_bitmap_unref (folder_mask);
  900.   }
  901.   
  902.   /*  Page 3  */
  903.   page = log_page =
  904.     user_install_notebook_append_page (GTK_NOTEBOOK (notebook),
  905.                        _("User Installation Log"),
  906.                        NULL);
  907.  
  908.   /*  Page 4  */
  909.   page = tuning_page = 
  910.     user_install_notebook_append_page (GTK_NOTEBOOK (notebook),
  911.                        _("GIMP Performance Tuning"),
  912.                        _("Click \"Continue\" to accept the settings above."));
  913.   
  914.   add_label (GTK_BOX (page),
  915.          _("For optimal GIMP performance, some settings may have to be adjusted."));
  916.  
  917.   sep = gtk_hseparator_new ();
  918.   gtk_box_pack_start (GTK_BOX (page), sep, FALSE, FALSE, 2);
  919.   gtk_widget_show (sep);
  920.  
  921.   /*  Page 5  */
  922.   page = resolution_page = 
  923.     user_install_notebook_append_page (GTK_NOTEBOOK (notebook),
  924.                        _("Monitor Resolution"),
  925.                        _("Click \"Continue\" to start The GIMP."));
  926.   
  927.   add_label (GTK_BOX (resolution_page),
  928.          _("To display images in their natural size, "
  929.            "GIMP needs to know your monitor resolution."));
  930.  
  931.   sep = gtk_hseparator_new ();
  932.   gtk_box_pack_start (GTK_BOX (page), sep, FALSE, FALSE, 2);
  933.   gtk_widget_show (sep);
  934.  
  935.   /*  EEK page  */
  936.   page = user_install_notebook_append_page (GTK_NOTEBOOK (notebook),
  937.                         _("Aborting Installation..."),
  938.                         NULL);
  939.  
  940.   user_install_notebook_set_page (GTK_NOTEBOOK (notebook), 0);
  941.  
  942.   gtk_widget_show (dialog);
  943. }
  944.  
  945.  
  946. /*********************/
  947. /*  Local functions  */
  948.  
  949. #ifdef G_OS_WIN32
  950.  
  951. static gchar *install_error_message;
  952.  
  953. static int
  954. copy_file (gchar *source,
  955.        gchar *dest)
  956. {
  957.   char buffer[4096];
  958.   FILE *sfile, *dfile;
  959.   int nbytes;
  960.  
  961.   sfile = fopen (source, "rb");
  962.   if (sfile == NULL)
  963.     {
  964.       install_error_message = g_strdup_printf (_("Cannot open %s for reading"),
  965.                            source);
  966.       return -1;
  967.     }
  968.  
  969.   dfile = fopen (dest, "wb");
  970.   if (dfile == NULL)
  971.     {
  972.       install_error_message = g_strdup_printf (_("Cannot open %s for writing"),
  973.                            dest);
  974.       fclose (sfile);
  975.       return -1;
  976.     }
  977.  
  978.   while ((nbytes = fread (buffer, 1, sizeof (buffer), sfile)) > 0)
  979.     {
  980.       if (fwrite (buffer, 1, nbytes, dfile) < nbytes)
  981.     {
  982.       install_error_message = g_strdup_printf (_("Error while writing %s"),
  983.                            dest);
  984.       fclose (sfile);
  985.       fclose (dfile);
  986.       return -1;
  987.     }
  988.     }
  989.  
  990.   if (ferror (sfile))
  991.     {
  992.       install_error_message = g_strdup_printf (_("Error while reading %s"),
  993.                            source);
  994.       fclose (sfile);
  995.       fclose (dfile);
  996.       return -1;
  997.     }
  998.  
  999.   fclose (sfile);
  1000.   fclose (dfile);
  1001.   return 0;
  1002. }
  1003.  
  1004. static int
  1005. copy_directory (gchar *source,
  1006.         gchar *dest)
  1007. {
  1008.   DIR *sdir;
  1009.   struct dirent *entry;
  1010.   gchar source_dir_name[1000];
  1011.   gchar dest_dir_name[1000];
  1012.   gchar source_file_name[1000];
  1013.   gchar dest_file_name[1000];
  1014.   struct stat st;
  1015.  
  1016.   strncpy (source_dir_name, source, sizeof (source_dir_name));
  1017.   if (source_dir_name[strlen (source_dir_name) - 1] == G_DIR_SEPARATOR)
  1018.     source_dir_name[strlen (source_dir_name) - 1] = '\0';
  1019.  
  1020.   strncpy (dest_dir_name, dest, sizeof (dest_dir_name));
  1021.   if (dest_dir_name[strlen (dest_dir_name) - 1] == G_DIR_SEPARATOR)
  1022.     dest_dir_name[strlen (dest_dir_name) - 1] = '\0';
  1023.  
  1024.   sdir = opendir (source_dir_name);
  1025.   if (sdir == NULL)
  1026.     {
  1027.       install_error_message = g_strdup_printf (_("Cannot open directory %s"),
  1028.                            source_dir_name);
  1029.       return -1;
  1030.     }
  1031.  
  1032.   if (mkdir (dest_dir_name, 0666) == -1)
  1033.     {
  1034.       install_error_message = g_strdup_printf (_("Cannot create directory %s -- %s"),
  1035.                            dest_dir_name, g_strerror (errno));
  1036.       closedir (sdir);
  1037.       return -1;
  1038.     }
  1039.  
  1040.   while ((entry = readdir (sdir)) != NULL)
  1041.     {
  1042.       if (strcmp (entry->d_name, ".") == 0 ||
  1043.       strcmp (entry->d_name, "..") == 0)
  1044.     continue;
  1045.  
  1046.       g_snprintf (source_file_name, sizeof (source_file_name), "%s%c%s",
  1047.           source_dir_name, G_DIR_SEPARATOR, entry->d_name);
  1048.  
  1049.       g_snprintf (dest_file_name, sizeof (dest_file_name), "%s%c%s",
  1050.           dest_dir_name, G_DIR_SEPARATOR, entry->d_name);
  1051.  
  1052.       if (stat (source_file_name, &st) == -1)
  1053.     {
  1054.       install_error_message = g_strdup_printf (_("Cannot get status of file %s"),
  1055.                            source_file_name);
  1056.       closedir (sdir);
  1057.       return -1;
  1058.     }
  1059.  
  1060.       if (S_ISDIR (st.st_mode))
  1061.     {
  1062.       if (copy_directory (source_file_name, dest_file_name) == -1)
  1063.         {
  1064.           closedir (sdir);
  1065.           return -1;
  1066.         }
  1067.     }
  1068.       else if (S_ISREG (st.st_mode))
  1069.     {
  1070.       if (copy_file (source_file_name, dest_file_name) == -1)
  1071.         {
  1072.           closedir (sdir);
  1073.           return -1;
  1074.         }
  1075.     }
  1076.     }
  1077.   closedir (sdir);
  1078.  
  1079.   return 0;
  1080. }
  1081.  
  1082. #endif
  1083.  
  1084. static gboolean
  1085. user_install_run (void)
  1086. {
  1087. #ifndef G_OS_WIN32
  1088.   FILE *pfp;
  1089.   gchar buffer[2048];
  1090.   struct stat stat_buf;
  1091.   gint err;
  1092.   gboolean executable = TRUE;
  1093.  
  1094.   /*  Generate output  */
  1095.   g_snprintf (buffer, sizeof (buffer), "%s" G_DIR_SEPARATOR_S USER_INSTALL,
  1096.           gimp_data_directory ());
  1097.  
  1098.   if ((err = stat (buffer, &stat_buf)) != 0)
  1099.     {
  1100.       gchar *str;
  1101.       
  1102.       str = g_strdup_printf (_("%s does not exist.\n"
  1103.                                "Cannot install."), buffer);
  1104.       add_label (GTK_BOX (log_page), str);
  1105.       g_free (str);
  1106.  
  1107.       executable = FALSE;
  1108.     }
  1109. #ifdef S_IXUSR
  1110.   else if (! (S_IXUSR & stat_buf.st_mode) || ! (S_IRUSR & stat_buf.st_mode))
  1111.     {
  1112.       gchar *str;
  1113.       
  1114.       str = g_strdup_printf (_("%s has invalid permissions.\n"
  1115.                                "Cannot install."), buffer);
  1116.       add_label (GTK_BOX (log_page), str);
  1117.       g_free (str);
  1118.  
  1119.       executable = FALSE;
  1120.     }
  1121. #endif
  1122.  
  1123.   if (executable)
  1124.     {
  1125. #ifndef __EMX__
  1126.       g_snprintf (buffer, sizeof(buffer), "%s" G_DIR_SEPARATOR_S USER_INSTALL " %s %s %s %s",
  1127.           gimp_data_directory (),
  1128.           "2>&1",
  1129.           gimp_data_directory(), gimp_directory (), gimp_sysconf_directory());
  1130. #else
  1131.       g_snprintf (buffer, sizeof(buffer), "cmd.exe /c %s" G_DIR_SEPARATOR_S USER_INSTALL " %s %s %s",
  1132.           gimp_data_directory (), gimp_data_directory(),
  1133.           gimp_directory (), gimp_sysconf_directory());
  1134.       {
  1135.     char *s = buffer + 10;
  1136.     while (*s)
  1137.       {
  1138.         if (*s == '/') *s = '\\';
  1139.         s++;
  1140.       }
  1141.       }
  1142. #endif
  1143.  
  1144.       /* urk - should really use something better than popen(), since
  1145.        * we can't tell if the installation script failed --austin */
  1146.       if ((pfp = popen (buffer, "r")) != NULL)
  1147.     {
  1148.       GtkWidget *table;
  1149.       GtkWidget *log_text;
  1150.       GtkWidget *vsb;
  1151.       GtkAdjustment *vadj;
  1152.  
  1153.       table = gtk_table_new (1, 2, FALSE);
  1154.       gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
  1155.       gtk_box_pack_start (GTK_BOX (log_page), table, TRUE, TRUE, 0);
  1156.  
  1157.       vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
  1158.       vsb  = gtk_vscrollbar_new (vadj);
  1159.       log_text = gtk_text_new (NULL, vadj);
  1160.  
  1161.       gtk_table_attach (GTK_TABLE (table), vsb, 1, 2, 0, 1,
  1162.                 GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
  1163.       gtk_table_attach (GTK_TABLE (table), log_text, 0, 1, 0, 1,
  1164.                 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
  1165.                 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
  1166.                 0, 0);
  1167.  
  1168.       gtk_widget_show (vsb);
  1169.       gtk_widget_show (log_text);
  1170.       gtk_widget_show (table);
  1171.  
  1172.       while (fgets (buffer, sizeof (buffer), pfp))
  1173.         gtk_text_insert (GTK_TEXT (log_text), NULL, NULL, NULL, buffer, -1);
  1174.       pclose (pfp);
  1175.  
  1176.       add_label (GTK_BOX (log_page),
  1177.              _("Did you notice any error messages in the lines above?\n"
  1178.                "If not, installation was successful!\n"
  1179.                "Otherwise, quit and investigate the possible reason..."));
  1180.     }
  1181.       else
  1182.     executable = FALSE;
  1183.     }
  1184.  
  1185.   if (executable)
  1186.     {
  1187.       gtk_object_set_data (GTK_OBJECT (log_page), "footer",
  1188.            _("Click \"Continue\" to complete GIMP installation."));
  1189.     }
  1190.   else
  1191.     {
  1192.       add_label (GTK_BOX (log_page),
  1193.          _("Installation failed.  Contact system administrator."));
  1194.     }
  1195.  
  1196.   return executable;
  1197. #else
  1198.   GtkWidget *table;
  1199.   GtkWidget *log_text;
  1200.   GtkWidget *vsb;
  1201.   GtkAdjustment *vadj;
  1202.   gchar dest[1000];
  1203.   gchar source[1000];
  1204.   gchar log_line[1000];
  1205.   gint i;
  1206.   
  1207.   table = gtk_table_new (1, 2, FALSE);
  1208.   gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
  1209.   gtk_box_pack_start (GTK_BOX (log_page), table, TRUE, TRUE, 0);
  1210.   
  1211.   vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
  1212.   vsb  = gtk_vscrollbar_new (vadj);
  1213.   log_text = gtk_text_new (NULL, vadj);
  1214.   
  1215.   gtk_table_attach (GTK_TABLE (table), vsb, 1, 2, 0, 1,
  1216.             GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
  1217.   gtk_table_attach (GTK_TABLE (table), log_text, 0, 1, 0, 1,
  1218.             GTK_EXPAND | GTK_SHRINK | GTK_FILL,
  1219.             GTK_EXPAND | GTK_SHRINK | GTK_FILL,
  1220.             0, 0);
  1221.   
  1222.   gtk_widget_show (vsb);
  1223.   gtk_widget_show (log_text);
  1224.   gtk_widget_show (table);
  1225.  
  1226.   for (i = 0; i < num_tree_items; i++)
  1227.     {
  1228.       if (i == 0)
  1229.     {
  1230.       g_snprintf (log_line, sizeof (log_line), _("Creating directory %s\n"),
  1231.               gimp_directory ());
  1232.       gtk_text_insert (GTK_TEXT (log_text), NULL, NULL, NULL,
  1233.                log_line, -1);
  1234.       if (mkdir (gimp_directory (), 0666) == -1)
  1235.         {
  1236.           install_error_message = g_strdup_printf (_("Cannot create directory -- %s"),
  1237.                                g_strerror (errno));
  1238.           goto break_out_of_loop;
  1239.         }
  1240.       gtk_text_insert (GTK_TEXT (log_text), NULL, NULL, NULL,
  1241.                _("  Success\n"), -1);
  1242.     }
  1243.       g_snprintf (dest, sizeof (dest), "%s%c%s",
  1244.           gimp_directory (), G_DIR_SEPARATOR, tree_items[i].text);
  1245.       switch (tree_items[i].type)
  1246.     {
  1247.     case TREE_ITEM_DONT:
  1248.       break;
  1249.  
  1250.     case TREE_ITEM_MKDIR_ONLY:
  1251.       g_snprintf (log_line, sizeof (log_line), _("Creating directory %s\n"),
  1252.               dest);
  1253.       gtk_text_insert (GTK_TEXT (log_text), NULL, NULL, NULL,
  1254.                log_line, -1);
  1255.       if (mkdir (dest, 0666) == -1)
  1256.         {
  1257.           install_error_message = g_strdup_printf (_("Cannot create directory -- %s"),
  1258.                                g_strerror (errno));
  1259.           goto break_out_of_loop;
  1260.         }
  1261.       break;
  1262.  
  1263.     case TREE_ITEM_FROM_SYSCONF_DIR:
  1264.       g_snprintf (source, sizeof (source), "%s%c%s",
  1265.               gimp_sysconf_directory (), G_DIR_SEPARATOR,
  1266.               tree_items[i].source_filename ?
  1267.               tree_items[i].source_filename : tree_items[i].text);
  1268.       goto do_copy;
  1269.  
  1270.     case TREE_ITEM_FROM_DATA_DIR:
  1271.       g_snprintf (source, sizeof (source), "%s%c%s",
  1272.               gimp_data_directory (), G_DIR_SEPARATOR,
  1273.               tree_items[i].source_filename ?
  1274.               tree_items[i].source_filename : tree_items[i].text);
  1275.     do_copy:
  1276.       if (tree_items[i].directory)
  1277.         {
  1278.           g_snprintf (log_line, sizeof (log_line), _("Populating directory %s from %s\n"),
  1279.               dest, source);
  1280.           gtk_text_insert (GTK_TEXT (log_text), NULL, NULL, NULL,
  1281.                    log_line, -1);
  1282.           
  1283.           if (copy_directory (source, dest) == -1)
  1284.         goto break_out_of_loop;
  1285.         }
  1286.       else
  1287.         {
  1288.           g_snprintf (log_line, sizeof (log_line), _("Copying file %s from %s\n"),
  1289.               dest, source);
  1290.           gtk_text_insert (GTK_TEXT (log_text), NULL, NULL, NULL,
  1291.                    log_line, -1);
  1292.           if (copy_file (source, dest) == -1)
  1293.         goto break_out_of_loop;
  1294.         }
  1295.       break;
  1296.  
  1297.     default:
  1298.       g_assert_not_reached ();
  1299.     }
  1300.       if (tree_items[i].type != TREE_ITEM_DONT)
  1301.     gtk_text_insert (GTK_TEXT (log_text), NULL, NULL, NULL,
  1302.              _("  Success\n"), -1);
  1303.     }
  1304.  
  1305.  break_out_of_loop:
  1306.  
  1307.   if (i < num_tree_items)
  1308.     {
  1309.       g_snprintf (log_line, sizeof (log_line), _("  Failure -- %s\n"),
  1310.           install_error_message);
  1311.       gtk_text_insert (GTK_TEXT (log_text), NULL, NULL, NULL,
  1312.                log_line, -1);
  1313.       add_label (GTK_BOX (log_page),
  1314.          _("Installation failed.  Contact system administrator."));
  1315.       return FALSE;
  1316.     }
  1317.  
  1318.   return TRUE;
  1319. #endif
  1320. }
  1321.  
  1322. static GtkObject *tile_cache_adj    = NULL;
  1323. static GtkWidget *swap_path_filesel = NULL;
  1324. static GtkWidget *xserver_toggle    = NULL;
  1325. static GtkWidget *resolution_entry  = NULL;
  1326.  
  1327. static void
  1328. user_install_tuning (void)
  1329. {
  1330.   GtkWidget *hbox;
  1331.   GtkWidget *sep;
  1332.   GtkWidget *label;
  1333.   GtkWidget *memsize;
  1334.  
  1335.   /*  tile cache size  */
  1336.   add_label (GTK_BOX (tuning_page),
  1337.          _("GIMP uses a limited amount of memory to store image data, the so-called\n"
  1338.            "\"Tile Cache\". You should adjust its size to fit into memory. Consider\n"
  1339.            "the amount of memory used by other running processes."));
  1340.  
  1341.   hbox = gtk_hbox_new (FALSE, 8);
  1342.   gtk_box_pack_start (GTK_BOX (tuning_page), hbox, FALSE, FALSE, 0);
  1343.   gtk_widget_show (hbox);
  1344.   
  1345.   tile_cache_adj = gtk_adjustment_new (tile_cache_size, 
  1346.                        0, (4069.0 * 1024 * 1024), 1.0, 1.0, 0.0);
  1347.   memsize = gimp_mem_size_entry_new (GTK_ADJUSTMENT (tile_cache_adj));
  1348.   gtk_box_pack_end (GTK_BOX (hbox), memsize, FALSE, FALSE, 0);
  1349.   gtk_widget_show (memsize);
  1350.  
  1351.   label = gtk_label_new (_("Tile Cache Size:"));
  1352.   PAGE_STYLE (label);
  1353.   gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
  1354.   gtk_widget_show (label);
  1355.   
  1356.   sep = gtk_hseparator_new ();
  1357.   gtk_box_pack_start (GTK_BOX (tuning_page), sep, FALSE, FALSE, 2);
  1358.   gtk_widget_show (sep);
  1359.  
  1360.   /*  swap file location  */
  1361.   add_label (GTK_BOX (tuning_page),
  1362.          _("All image and undo data which doesn't fit into the Tile Cache will be\n"
  1363.            "written to a swap file. This file should be located on a local filesystem\n"
  1364.            "with enough free space (several hundred MB). On a UNIX system, you\n"
  1365.            "may want to use the system-wide temp-dir (\"/tmp\" or \"/var/tmp\")."));
  1366.  
  1367.   hbox = gtk_hbox_new (FALSE, 8);
  1368.   gtk_box_pack_start (GTK_BOX (tuning_page), hbox, FALSE, FALSE, 0);
  1369.   gtk_widget_show (hbox);
  1370.   
  1371.   swap_path_filesel = gimp_file_selection_new (_("Select Swap Dir"), swap_path,
  1372.                            TRUE, TRUE);
  1373.   gtk_box_pack_end (GTK_BOX (hbox), swap_path_filesel, FALSE, FALSE, 0);
  1374.   gtk_widget_show (swap_path_filesel);
  1375.  
  1376.   label = gtk_label_new (_("Swap Directory:"));
  1377.   PAGE_STYLE (label);
  1378.   gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
  1379.   gtk_widget_show (label);
  1380. }
  1381.  
  1382. static void
  1383. user_install_tuning_done (void)
  1384. {
  1385. }
  1386.  
  1387. static void
  1388. user_install_resolution_calibrate (GtkWidget *button,
  1389.                    gpointer   data)
  1390. {
  1391.   resolution_calibrate_dialog (resolution_entry, 
  1392.                    title_style, page_style,
  1393.                    GTK_SIGNAL_FUNC (user_install_corner_expose));
  1394. }
  1395.  
  1396. static void
  1397. user_install_resolution (void)
  1398. {
  1399.   GtkWidget *hbox;
  1400.   GtkWidget *sep;
  1401.   GimpChainButton *chain;
  1402.   GtkWidget *button;
  1403.   GList     *list; 
  1404.   gchar     *pixels_per_unit;
  1405.   gdouble    xres, yres;
  1406.   gchar     *str;
  1407.  
  1408.   gdisplay_xserver_resolution (&xres, &yres);
  1409.  
  1410.   add_label (GTK_BOX (resolution_page),
  1411.          _("GIMP can obtain this information from the windowing system.\n"
  1412.            "However, usually this does not give useful values."));
  1413.   
  1414.   hbox = gtk_hbox_new (FALSE, 0);
  1415.   gtk_box_pack_start (GTK_BOX (resolution_page), hbox, FALSE, FALSE, 0);
  1416.   gtk_widget_show (hbox);
  1417.  
  1418.   str = g_strdup_printf (_("Get Resolution from windowing system (Currently %d x %d dpi)"),
  1419.              ROUND (xres), ROUND (yres));
  1420.   xserver_toggle = gtk_check_button_new_with_label (str);
  1421.   g_free (str);
  1422.  
  1423.   PAGE_STYLE (GTK_BIN (xserver_toggle)->child);
  1424.   gtk_box_pack_end (GTK_BOX (hbox), xserver_toggle, FALSE, FALSE, 0);
  1425.   gtk_widget_show (xserver_toggle);
  1426.  
  1427.   sep = gtk_hseparator_new ();
  1428.   gtk_box_pack_start (GTK_BOX (resolution_page), sep, FALSE, FALSE, 2);
  1429.   gtk_widget_show (sep);
  1430.  
  1431.   add_label (GTK_BOX (resolution_page),
  1432.          _("Alternatively, you can set the monitor resolution manually."));
  1433.  
  1434.   hbox = gtk_hbox_new (FALSE, 0);
  1435.   gtk_box_pack_start (GTK_BOX (resolution_page), hbox, FALSE, FALSE, 0);
  1436.   gtk_widget_show (hbox);
  1437.   
  1438.   pixels_per_unit = g_strconcat (_("Pixels"), "/%s", NULL);
  1439.   resolution_entry =
  1440.     gimp_coordinates_new (GIMP_UNIT_INCH, pixels_per_unit,
  1441.               FALSE, FALSE, 75,
  1442.               GIMP_SIZE_ENTRY_UPDATE_RESOLUTION,
  1443.               abs (monitor_xres - monitor_yres) < GIMP_MIN_RESOLUTION,
  1444.               FALSE,
  1445.               _("Monitor Resolution X:"),
  1446.               monitor_xres,
  1447.               1.0,
  1448.               GIMP_MIN_RESOLUTION,
  1449.               GIMP_MAX_RESOLUTION,
  1450.               0, 0,
  1451.               _("Y:"),
  1452.               monitor_yres,
  1453.               1.0,
  1454.               GIMP_MIN_RESOLUTION,
  1455.               GIMP_MAX_RESOLUTION,
  1456.               0, 0);
  1457.   g_free (pixels_per_unit);
  1458.  
  1459.   chain = GIMP_COORDINATES_CHAINBUTTON (resolution_entry);
  1460.   PAGE_STYLE (GTK_WIDGET (chain->line1));
  1461.   PAGE_STYLE (GTK_WIDGET (chain->line2));
  1462.   gtk_object_set_data (GTK_OBJECT (resolution_entry), "chain_button", chain);
  1463.  
  1464.   for (list = GTK_TABLE (resolution_entry)->children;
  1465.        list;
  1466.        list = g_list_next (list))
  1467.     {
  1468.       GtkTableChild *child = (GtkTableChild *) list->data;
  1469.  
  1470.       if (child && GTK_IS_LABEL (child->widget))
  1471.     PAGE_STYLE (GTK_WIDGET (child->widget));
  1472.     }
  1473.  
  1474.   gtk_box_pack_end (GTK_BOX (hbox), resolution_entry, FALSE, FALSE, 0);
  1475.   gtk_widget_show (resolution_entry);
  1476.  
  1477.   sep = gtk_hseparator_new ();
  1478.   gtk_box_pack_start (GTK_BOX (resolution_page), sep, FALSE, FALSE, 2);
  1479.   gtk_widget_show (sep);
  1480.  
  1481.   add_label (GTK_BOX (resolution_page),
  1482.          _("You can also press the \"Calibrate\" button to open a window\n"
  1483.            "which lets you determine your monitor resolution interactively."));
  1484.  
  1485.   hbox = gtk_hbox_new (FALSE, 0);
  1486.   gtk_box_pack_start (GTK_BOX (resolution_page), hbox, FALSE, FALSE, 0);
  1487.   gtk_widget_show (hbox);
  1488.  
  1489.   button = gtk_button_new_with_label (_("Calibrate"));
  1490.   gtk_misc_set_padding (GTK_MISC (GTK_BIN (button)->child), 4, 0);
  1491.   gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
  1492.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  1493.               GTK_SIGNAL_FUNC (user_install_resolution_calibrate),
  1494.               NULL);
  1495.   gtk_widget_show (button);
  1496.   
  1497.   gtk_object_set_data (GTK_OBJECT (xserver_toggle), "inverse_sensitive",
  1498.                resolution_entry);
  1499.   gtk_object_set_data (GTK_OBJECT (resolution_entry), "inverse_sensitive",
  1500.                button);
  1501.   gtk_signal_connect (GTK_OBJECT (xserver_toggle), "toggled",
  1502.               GTK_SIGNAL_FUNC (gimp_toggle_button_sensitive_update),
  1503.               NULL);
  1504.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (xserver_toggle),
  1505.                 using_xserver_resolution);
  1506. }
  1507.  
  1508. static void
  1509. user_install_resolution_done (void)
  1510. {
  1511.   GList *update = NULL;
  1512.   GList *remove = NULL;
  1513.  
  1514.   gint      new_tile_cache_size;
  1515.   gchar    *new_swap_path;
  1516.   gboolean  new_using_xserver_resolution;
  1517.   gdouble   new_monitor_xres;
  1518.   gdouble   new_monitor_yres;
  1519.   
  1520.   new_tile_cache_size = GTK_ADJUSTMENT (tile_cache_adj)->value;
  1521.   new_swap_path =
  1522.     gimp_file_selection_get_filename (GIMP_FILE_SELECTION (swap_path_filesel));
  1523.   new_using_xserver_resolution =
  1524.     gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (xserver_toggle));
  1525.   new_monitor_xres =
  1526.     gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (resolution_entry), 0);
  1527.   new_monitor_yres =
  1528.     gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (resolution_entry), 1);
  1529.  
  1530.   if (tile_cache_size != new_tile_cache_size)
  1531.     {
  1532.       tile_cache_size = new_tile_cache_size;
  1533.       update = g_list_append (update, "tile-cache-size");
  1534.     }
  1535.   if (swap_path && new_swap_path && 
  1536.       strcmp (swap_path, new_swap_path))
  1537.     {
  1538.       g_free (swap_path);      swap_path = new_swap_path;
  1539.       update = g_list_append (update, "swap-path");
  1540.     }
  1541.   if (using_xserver_resolution != new_using_xserver_resolution ||
  1542.       ABS (monitor_xres - new_monitor_xres) > GIMP_MIN_RESOLUTION)
  1543.     {
  1544.       monitor_xres = new_monitor_xres;
  1545.       update = g_list_append (update, "monitor-xresolution");
  1546.     }
  1547.   if (using_xserver_resolution != new_using_xserver_resolution ||
  1548.       ABS (monitor_yres - new_monitor_yres) > GIMP_MIN_RESOLUTION)
  1549.     {
  1550.       monitor_yres = new_monitor_yres;
  1551.       update = g_list_append (update, "monitor-yresolution");
  1552.     }
  1553.  
  1554.   using_xserver_resolution = new_using_xserver_resolution;
  1555.  
  1556.   if (using_xserver_resolution)
  1557.     {
  1558.       /* special value of 0 for either x or y res in the gimprc file
  1559.        * means use the xserver's current resolution */
  1560.       monitor_xres = 0.0;
  1561.       monitor_yres = 0.0;
  1562.     }
  1563.  
  1564.   save_gimprc (&update, &remove);
  1565.  
  1566.   if (using_xserver_resolution)
  1567.     gdisplay_xserver_resolution (&monitor_xres, &monitor_yres);
  1568.  
  1569.   g_list_free (update);
  1570.   g_list_free (remove);
  1571. }
  1572.